package org.ghost.spring.cloud.config.client.demo.component.monitor;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.ghost.spring.cloud.config.client.demo.common.component.RequestContext;
import org.ghost.spring.cloud.config.client.demo.util.ExceptionUtil;
import org.ghost.spring.cloud.config.client.demo.util.JacksonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.function.Supplier;


/**
 * 服务监控器（记录日志等功能）
 */
@Aspect
@Component
public class ServiceMonitor {
    /**
     * 日志处理器
     */
    private final Logger logger = LoggerFactory.getLogger(ServiceMonitor.class);

    public ServiceMonitor() {
    }

    @Pointcut("execution(* org.ghost.spring.cloud.config.client.demo.service..*.*(..))")
    public void serviceMonitorLog() {
    }

    /**
     * 记录service方法前所有的日志
     *
     * @param joinPoint 不能为空
     */
    @Before(value = "serviceMonitorLog()")
    public void pointBeforeMethodInvoke(JoinPoint joinPoint) {
        StringBuilder sb = new StringBuilder("******** Starting : ")
                .append(joinPoint.getSignature().getDeclaringTypeName())
                .append(".").append(joinPoint.getSignature().getName())
                .append(logAllParamsInfo(joinPoint))
                .append(" ******");
        info(sb::toString);
    }


    @AfterReturning(pointcut = "serviceMonitorLog()", returning = "result", argNames = "result")
    public void pointAfterMethodInvoke(JoinPoint joinPoint, Object result) {
        info(() -> "******** ending : " + joinPoint.getSignature().getDeclaringTypeName()
                + "." + joinPoint.getSignature().getName() + " ******"
                + ";返回结果->" + JacksonUtil.useDefaultMapper().toJson(result));

        RequestContext.remove();
    }

    @AfterThrowing(pointcut = "serviceMonitorLog()", throwing = "exception", argNames = "exception")
    public void pointAfterThrowingMethodInvoke(JoinPoint joinPoint, Throwable exception) {
        info(() -> "******** throwing : " + joinPoint.getSignature().getDeclaringTypeName()
                + "." + joinPoint.getSignature().getName() + " ******"
                + ";异常信息->" + ExceptionUtil.getExceptionStack(exception));

        //交给@ControllerAdvice处理
        //RequestContext.remove();
    }

    /**
     * 记录切点当前方法所有的参数
     *
     * @param joinPoint 不能为空
     */
    private String logAllParamsInfo(JoinPoint joinPoint) {

        StringBuilder sb = new StringBuilder();
        try {
            Object[] args = joinPoint.getArgs();
            int index = 0;
            for (Object arg : args) {
                if (arg != null) {
                    sb.append(" param").append(index).append(": ").append(JacksonUtil.useDefaultMapper().toJson(arg));
                } else {
                    sb.append(" param").append(index).append(": null");
                }
                index++;
            }
        } catch (Exception ex) {
            info(() -> "***** ServiceMonitor ****  参数解析错误:" + ExceptionUtil.getExceptionStack(ex));
        }

        return sb.toString();
    }

    /**
     * debug级别日志输出
     *
     * @param supplier 不能为空
     */
    private void info(Supplier<String> supplier) {
        logger.info("debug: " + supplier.get());
    }

}
